[READ-ONLY] a fast, modern browser for the npm registry
at main 69 lines 2.2 kB view raw
1import * as v from 'valibot' 2import { PackageRouteParamsSchema } from '#shared/schemas/package' 3import type { NpmVersionDist } from '#shared/types' 4import { CACHE_MAX_AGE_ONE_HOUR, ERROR_PROVENANCE_FETCH_FAILED } from '#shared/utils/constants' 5import { 6 parseAttestationToProvenanceDetails, 7 type NpmAttestationsResponse, 8} from '#server/utils/provenance' 9 10/** 11 * GET /api/registry/provenance/:name/v/:version 12 * 13 * Returns parsed provenance details for a package version (build summary, source commit, build file, public ledger). 14 * Version is required. Returns null when the version has no attestations or parsing fails. 15 */ 16export default defineCachedEventHandler( 17 async event => { 18 const pkgParamSegments = getRouterParam(event, 'pkg')?.split('/') ?? [] 19 20 const { rawPackageName, rawVersion } = parsePackageParams(pkgParamSegments) 21 22 if (!rawVersion) { 23 throw createError({ 24 statusCode: 400, 25 message: 'Version is required for provenance.', 26 }) 27 } 28 29 try { 30 const parsed = v.parse(PackageRouteParamsSchema, { 31 packageName: rawPackageName, 32 version: rawVersion, 33 }) as { packageName: string; version: string } 34 const { packageName, version } = parsed 35 36 const packument = await fetchNpmPackage(packageName) 37 const versionData = packument.versions[version] 38 if (!versionData) { 39 throw createError({ 40 statusCode: 404, 41 message: `Version ${version} not found for package ${packageName}.`, 42 }) 43 } 44 const dist = versionData.dist as NpmVersionDist | undefined 45 const attestationsUrl = dist?.attestations?.url 46 47 if (!attestationsUrl) { 48 return null 49 } 50 51 const response = await $fetch<NpmAttestationsResponse>(attestationsUrl) 52 const details = parseAttestationToProvenanceDetails(response) 53 return details 54 } catch (error: unknown) { 55 handleApiError(error, { 56 statusCode: 502, 57 message: ERROR_PROVENANCE_FETCH_FAILED, 58 }) 59 } 60 }, 61 { 62 maxAge: CACHE_MAX_AGE_ONE_HOUR, 63 swr: true, 64 getKey: event => { 65 const pkg = getRouterParam(event, 'pkg') ?? '' 66 return `provenance:v1:${pkg.replace(/\/+$/, '').trim()}` 67 }, 68 }, 69)